<template>
  <div :class="prefixCls">
    <div v-if="getItemActions.length" class="actions flex mt-2 mb-2">
      <ButtonActions :data="getItemActions" @add="handleAdd" @del="handleDelMutil" />
    </div>
    <Scrollbar class="table-container">
      <table class="my-table w-full">
        <colgroup>
          <col class="max-w-10" width="40px" v-if="hasDel" />
          <col class="max-w-10" width="40px" />
          <template v-for="c in column" :key="c.label">
            <col v-if="c.ifShow" :width="c.width" />
          </template>
          <col width="150px" v-if="getActions.length" />
        </colgroup>
        <thead class="thead">
          <tr>
            <th v-if="hasDel">
              <Checkbox
                :disabled="!rawData.length"
                :checked="checkAll"
                @change="onCheckAllChange"
                :indeterminate="indeterminate"
              />
            </th>
            <th>序号</th>
            <template v-for="c in column" :key="c.label">
              <th v-if="c.ifShow" :class="c.class">{{ c.label }} </th>
            </template>
            <th class="t-action" v-if="getActions.length">操作</th>
          </tr>
        </thead>

        <template v-if="rawData.length">
          <Draggable
            group="form-draggable"
            class="tbody"
            tag="tbody"
            :component-data="{
              tag: 'tbody',
              type: 'transition-group',
              name: 'list',
            }"
            ghostClass="moving"
            :animation="180"
            :list="getPaginationList"
            :disabled="true"
            handle=".th-drag"
            item-key="key"
          >
            <template #item="{ element: item, index }">
              <tr class="tr-item" @click.capture="handleFocus(index)">
                <td v-if="hasDel"><Checkbox v-model:checked="item.check" /></td>
                <td class="th-drag">
                  <!-- <Icon icon="carbon:drag-vertical" /> -->
                  {{ index + 1 }}
                </td>
                <template v-for="tbItem in column" :key="tbItem.label">
                  <td v-if="tbItem.ifShow" :class="tbItem.class">
                    <div class="cell-item" v-if="!isDialogType">
                      <component
                        :is="componentMap.get(tbItem.component)"
                        v-model:value="item[tbItem.field]"
                        v-bind="
                          isFunction(tbItem.componentProps)
                            ? tbItem.componentProps({ formModel: item })
                            : tbItem.componentProps
                        "
                        :formValues="{ values: item }"
                        :placeholder="
                          createPlaceholderMessage(
                            tbItem.component === 'Hide' ? 'Input' : tbItem.component,
                            tbItem.label,
                          )
                        "
                        :disabled="disabled || tbItem.componentProps?.disabled"
                      />
                    </div>
                    <div class="dialog-item" v-else>
                      <div class="upload" v-if="showFilePreview(tbItem, item[tbItem.field])">
                        <HFileReview
                          :info="item[tbItem.field]"
                          labelField="fileName"
                          valueField="preUrl"
                        />
                      </div>
                      <div class="text" v-else>
                        {{
                          isArray(item[tbItem.field])
                            ? item[tbItem.field].join()
                            : item[tbItem.field]
                        }}
                      </div>
                    </div>
                  </td>
                </template>
                <td class="t-action" v-if="getActions.length">
                  <ButtonActions
                    @edit="handleEdit(item, index)"
                    :data="getActions"
                    @del="handleDel(index)"
                  />
                </td>
              </tr>
            </template>
          </Draggable>
        </template>
      </table>

      <HEmpty v-if="rawData.length <= 0" />
      <Pagination
        class="text-right"
        v-if="config.pageSize"
        showLessItems
        size="small"
        :pageSize="config.pageSize"
        :total="getTotal"
        @change="handlePageChange"
      />
    </Scrollbar>
    <FormModal
      v-if="isDialogType"
      :width="dialogWidth"
      @register="registerModal"
      @success="handleSuccess"
    />
  </div>
</template>

<script lang="ts" setup name="SubTable">
  import { ref, onMounted, computed, nextTick, watch } from 'vue';
  import type { Component } from 'vue';
  import QueryString from 'qs';

  import Draggable from 'vuedraggable';
  import { HChooseUser } from '/@/components/HChooseUser';
  import HEmpty from '/@/components/HEmpty/index.vue';
  import ButtonActions from '/@/components/ModelTable/src/components/ButtonActions.vue';
  import { Scrollbar } from '/@/components/Scrollbar';
  import { createPlaceholderMessage } from '/@/components/Form/src/helper';

  import { Checkbox } from 'ant-design-vue';
  import { HFileReview } from '/@/components/HFileReview';

  import { useMessage } from '/@/hooks/web/useMessage';
  import { useModal } from '/@/components/Modal';
  import { usePagination } from '/@/hooks/web/usePagination';

  import { isObject, isArray, isFunction, isNullOrUnDef } from '/@/utils/is';
  import { toJson } from '/@/utils';

  import { useDesign } from '/@/hooks/web/useDesign';
  import { getFormSchemas } from '/@/components/ModelTable/src/hooks/useComFormModel';
  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';

  import { getModelInstanceInfoApi } from '/@/api/config-center/model-design';
  import { getCSSValue } from '/@/utils';
  import { FormActionType } from '/@/components/Form/index';
  import { componentMap as VbenCmp } from '/@/components/Form/src/componentMap';
  import { Pagination } from 'ant-design-vue';
  const FormModal = createAsyncComponent(
    () => import('/@/components/ModelTable/src/components/FormModal.vue'),
  );

  //  按钮显示
  const BTN_AUTH = '1';
  enum OperationType {
    DIALOG = 'dialog',
    BATCH = 'batch',
  }

  enum BtnLocationType {
    ITEM = 'item',
    ACTION = 'action',
  }
  const componentMap = new Map<string, Component>();
  //注册vben控件库
  VbenCmp.forEach((value, key) => {
    componentMap.set(key, value);
  });

  componentMap.set('Draggable', Draggable);
  componentMap.set('HFileReview', HFileReview);
  componentMap.set('ChooseUser', HChooseUser);

  interface SubTableConfig {
    modelId: string;
    width?: string;
    dialogWidth?: string;
    windowParams?: string;
    operationType: OperationType;
    tableColumn: Indexable[];
    tableBtn: Indexable[];
    column?: Indexable[];
    pageSize?: number;
  }
  const { createMessage } = useMessage();

  // const { onFieldChange } = Form.useInjectFormItemContext();
  const { prefixCls } = useDesign('SubTable');
  const props = withDefaults(
    defineProps<{
      value?: any[];
      disabled?: boolean;
      config?: SubTableConfig;
      formState?: Indexable;
      formValues?: Indexable;
      callbackMap?: {
        formActionType?: FormActionType; //当前表单方法
        parentFormActionType?: Partial<FormActionType>; // 父级表单方法
      };
    }>(),
    {
      // @ts-ignore
      config: () => ({
        modelId: '',
        tableBtn: [],
        operationType: 'batch',
        tableColumn: [],
      }),
      callbackMap: () => ({}),
    },
  );
  const emit = defineEmits<{
    (e: 'change', value: any): any;
    (e: 'delete', value: any): any;
  }>();

  const isLoad = ref(true);
  const rawData = ref<Indexable[]>(props.value || []);
  const { getPaginationList, getTotal, setCurrentPage } = usePagination(
    rawData,
    props.config.pageSize || 999999,
  );
  function handlePageChange(page: number) {
    setCurrentPage(page);
  }

  const currentIndex = ref(0);
  onMounted(async () => {
    await getColumn();
    isLoad.value = false;
  });

  const [registerModal, { openModal }] = useModal();

  watch(
    () => rawData.value,
    (v) => {
      if (isLoad.value) return;
      emit('change', v);
    },
    { deep: true },
  );

  watch(
    () => props.value,
    (after) => {
      if (isLoad.value) {
        isLoad.value = false;
      }

      rawData.value = after || [];
    },
  );
  // 查表单配置的参数
  const params = computed(() => {
    const { windowParams = '' } = props.config;
    const ret = QueryString.parse(windowParams, {
      ignoreQueryPrefix: true,
    });

    const { params = {} } = props.formState || {};
    const { values = {} } = props.formValues || {};

    return {
      ...ret,
      ...params,
      ...values,
    };
  });
  //  交互类型
  const isDialogType = computed(() => {
    const { operationType } = props.config;

    return operationType === OperationType.DIALOG;
  });
  const dialogWidth = computed(() => {
    const { dialogWidth } = props.config;

    return getCSSValue(dialogWidth, '60%');
  });

  // 列表上方按钮
  const getItemActions = computed(() => {
    const { tableBtn = [] } = props.config;

    if (props.disabled) return [];
    return tableBtn.filter(
      (bt) => bt.permission === BTN_AUTH && bt.location === BtnLocationType.ITEM,
    );
  });
  // 批量删除
  const hasDel = computed(() => {
    return getItemActions.value.findIndex((bt) => bt.eventType === 'del') > -1;
  });
  // 列表操作按钮
  const getActions = computed(() => {
    const { tableBtn } = props.config;
    if (props.disabled) return [];
    return tableBtn.filter(
      (bt) => bt.permission === BTN_AUTH && bt.location === BtnLocationType.ACTION,
    );
  });

  const column = ref<any[]>([]);
  const hideFields = ref<any[]>([]);

  async function getColumn() {
    const { tableColumn, modelId, width } = props.config;
    tableColumn.forEach((el) => {
      el.width = getCSSValue(width || el.width, '110px');
    });

    //  弹框类型无需处理表单
    if (isDialogType.value) {
      column.value = tableColumn;
      return;
    }

    if (!modelId) {
      return;
    }

    const { formDesignInfo } = await getModelInstanceInfoApi(modelId, params.value);

    // 查出绑定的表单 并获取表单的配置替换成列表展示
    const { formConfig, hideField } = getFormSchemas(
      formDesignInfo!,
      {
        modelId,
        params: params.value,
      },
      {
        getRecord,
        parentFormActionType: props.callbackMap.formActionType || {},
      },
    );

    const { schemas } = formConfig || {};

    hideFields.value = hideField || [];
    column.value = tableColumn.map((el) => {
      const item = schemas!.find((sc) => sc.field === el.field);
      if (item) {
        // @ts-ignore
        item.width = getCSSValue(width || el.width, '110px');
        item.ifShow = el.ifShow;
        item.label = el.label;
        // @ts-ignore
        item.componentProps!.disabled = item.dynamicDisabled as boolean;

        return item;
      } else {
        el.component = 'Input';
        el.width = getCSSValue(width || el.width, '110px');
        return el;
      }
    });

    nextTick(() => {
      // eslint-disable-next-line vue/no-mutating-props
      props.config.column = column.value;
    });
  }
  function handleFocus(idx) {
    currentIndex.value = idx;
  }
  function getRecord() {
    return rawData.value[currentIndex.value];
  }
  function isEmpty(v) {
    return isNullOrUnDef(v) || v === '';
  }
  function getDefValue() {
    const ret = {};

    column.value.forEach(({ field, defaultValue }) => {
      if (!isEmpty(defaultValue)) {
        ret[field] = defaultValue;
      }
    });

    hideFields.value.forEach(({ field, defaultValue }) => {
      if (!isEmpty(defaultValue)) {
        ret[field] = defaultValue;
      }
    });

    return ret;
  }
  async function handleSuccess(data, { index }) {
    if (index === -1) {
      rawData.value.push(data);
      return;
    }
    rawData.value.splice(index, 1, data);
  }

  function handleEdit(record: Recordable, index) {
    openModal(true, {
      index,
      onlyData: true,
      dataModelId: props.config.modelId,
      retFormDesignInfo: record,
      params: params.value,
      parentFormActionType: props.callbackMap.formActionType || {},
    });
  }
  function handleAdd() {
    if (isDialogType.value) {
      openModal(true, {
        onlyData: true,
        isCreate: true,
        index: -1,
        params: params.value,
        dataModelId: props.config.modelId,
      });

      return;
    }

    const item = getDefValue();

    rawData.value.push(item);
    // onFieldChange();
  }
  function handleDel(index) {
    const item = rawData.value.splice(index, 1);
    emit('delete', item);
  }

  function handleDelMutil() {
    const arr = rawData.value;
    const data = arr.filter((el) => el.check);
    if (!data.length) {
      createMessage.warn('请先选择要删除的列');
      return;
    }

    emit('delete', data);

    rawData.value = arr.filter((el) => !el.check);
  }
  const checkAll = computed(() => {
    if (!rawData.value.length) {
      return false;
    } else {
      const arr = rawData.value.filter((el) => !el.check);
      return !arr.length;
    }
  });
  const indeterminate = computed(() => {
    const arr = rawData.value || [];
    const len = arr.filter((el) => el.check).length;
    const allLen = arr.length;

    if (len === allLen) return false;
    return !!arr.find((el) => el.check);
  });

  const onCheckAllChange = (e) => {
    for (const item of rawData.value) {
      item.check = e.target.checked;
    }
  };

  function showFilePreview(config: Indexable, value: any) {
    //  弹框类型无需处理表单
    if (isDialogType.value) {
      // 处理下拉数据
      if (isArray(value)) {
        return isObject(value[0]);
      }
      return isArray(toJson(value));
    }
    return config.component === 'Upload';
  }
</script>

<style lang="less" scoped>
  @prefix-cls: ~'@{namespace}-SubTable';
  .@{prefix-cls}{
    .cell-fix {
      position: absolute;
        top: 0;
        bottom: 0;
        z-index: 2;
        width: 30px;
        transition: box-shadow 0.3s;
        content: '';
        pointer-events: none;
    }

    .table-container {
      position: relative;
      // overflow-x: auto;
      // ant-table-ping-left
      // ant-table-ping-left
      &::before,
      &::after {
        .cell-fix
      }

      &::after  {
        right: 0;
      }
    }

  .my-table {
    table-layout: fixed;
    border-radius: 4px 4px 0 0;
    box-sizing: border-box;
    text-align: left;
    color: #666;
    border-collapse: separate;
    border-spacing: 0;

    th,
    td {
      padding: 12px 8px;
      overflow-wrap: break-word;
    }

    .thead {
      white-space: nowrap;
      text-overflow: ellipsis;
      word-break: keep-all;

      th {
        font-weight: 500;
        background: @table-header-bg;
        border-bottom: 1px solid #f0f0f0;
        transition: background 0.3s ease;
      }
    }

    .tbody {
          box-sizing: border-box;
        }

    .tr-item {
      white-space: nowrap;
      text-overflow: ellipsis;
      word-break: keep-all;

      &:hover {
        box-shadow: @box-shadow-A1-base;


        td {
          background: @table-row-hover-bg;
        }
      }

        .th-drag {
          // &:hover {
          //   cursor: grab;
          //   background: #edf3fc;
          //   box-shadow: 0px 4px 4px -3px #dde6f1, inset 0px 1px 4px -3px #35629a;
          // }
        }

        td {
          background-color: @table-bg ;
          border-bottom: 1px solid @table-td-border;
        }
      }

      .t-action {
        position: sticky;
        right: 0;
        min-width: 100px;

        &::after {
          position: absolute;
          top: 0;
          bottom: -1px;
          left: 0;
          width: 30px;
          transform: translateX(-100%);
          transition: box-shadow 0.3s;
          content: '';
          pointer-events: none;
          box-shadow: inset -10px 0 8px -8px rgba(0, 0, 0, 0.15);
        }

      }
    }
  }
</style>
